<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { useBoolean } from '@sa/hooks';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { fetchAddVPN, fetchEditVPN, fetchGetAllVPNTemplateList } from '@/service/api';
import DeviceSelectModal from './device-select-modal.vue';
import type { DeviceSelectedMac } from './device-select-modal.vue';

defineOptions({
  name: 'VPNOperateDrawer'
});

interface Props {
  /** 操作类型 */
  operateType: NaiveUI.TableOperateType;
  /** 编辑行数据 */
  rowData?: TicketManageApi.VPNManage.VPN | null;
}

const props = defineProps<Props>();

interface Emits {
  (e: 'submitted'): void;
}

const emit = defineEmits<Emits>();

const visible = defineModel<boolean>('visible', {
  default: false
});

const { bool: loading, setBool: setLoading } = useBoolean();
const { bool: deviceModalVisible, setTrue: setDeviceModalVisible } = useBoolean();

const { formRef, validate, restoreValidation } = useNaiveForm();
const { createRequiredRule, createRequiredNumRule, createLengthRule } = useFormRules();

const title = computed(() => {
  const titles: Record<NaiveUI.TableOperateType, string> = {
    add: '新增量子配置',
    edit: '编辑量子配置'
  };
  return titles[props.operateType];
});

type Model = Pick<
  TicketManageApi.VPNManage.VPN,
  'id' | 'name' | 'ipsecTemplateId' | 'ikeKeys' | 'enable' | 'connectionStatus' | 'deviceMacA' | 'deviceMacB' | 'remark'
>;

const model = ref(createDefaultModel());

function createDefaultModel(): Model {
  return {
    id: null,
    name: '',
    deviceMacA: null,
    deviceMacB: null,
    ipsecTemplateId: null,
    ikeKeys: '',
    enable: true,
    connectionStatus: false,
    remark: ''
  };
}

type RuleKey = Extract<keyof Model, 'name' | 'ipsecTemplateId' | 'ikeKeys' | 'deviceMacA' | 'deviceMacB' | 'remark'>;

const rules: Record<RuleKey, CommonType.WithArray<App.Global.FormRule>> = {
  name: [createRequiredRule('请输入配置名称'), createLengthRule(64)],
  deviceMacA: [createRequiredRule('请选择组网设备')],
  deviceMacB: [createRequiredRule('请选择组网设备')],
  ipsecTemplateId: [createRequiredNumRule('请选择配置模板')],
  ikeKeys: [createRequiredRule('请输入IKE密钥'), createLengthRule(16)],
  remark: [createLengthRule(500)]
};

type LineStatus = 'connecting' | 'unconnected' | 'unenabled' | 'unset';
/** 组网设备连接状态 */
const lineStatus = computed<LineStatus>(() => {
  if (!model.value.deviceMacA || !model.value.deviceMacB) return 'unset'; /** 未配置完全 */
  if (model.value.enable) {
    if (model.value.connectionStatus) return 'connecting'; /** 连接中 */
    return 'unconnected'; /** 未连接 */
  }
  return 'unenabled';
});
/** 组网设备连接状态图标 */
const lineStatusIcon = computed(() => {
  const icons: Record<LineStatus, string> = {
    unset: 'ic-baseline-cancel',
    connecting: 'ic-baseline-security',
    unconnected: 'mdi-link-variant-off',
    unenabled: 'ic-baseline-block'
  };
  return icons[lineStatus.value];
});

/** 组网设备 MAC 集合 */
const deviceSelectedMac = computed<DeviceSelectedMac>(() => {
  if (model.value.deviceMacA && model.value.deviceMacB) {
    return [model.value.deviceMacA, model.value.deviceMacB];
  }
  return [];
});

function handleSelectDevice() {
  setDeviceModalVisible();
}

function handleInitModel() {
  model.value = createDefaultModel();

  if (props.operateType === 'edit' && props.rowData) {
    Object.assign(model.value, props.rowData);
  }
}

function closeDrawer() {
  visible.value = false;
}

function handleDeviceSelect(deviceList: TicketManageApi.DeviceManage.Device[]) {
  model.value.deviceMacA = deviceList[0]?.mac || null;
  model.value.deviceMacB = deviceList[1]?.mac || null;
  validate();
}

async function handleSubmit() {
  await validate();
  const params = {
    id: model.value.id,
    name: model.value.name,
    ipsecTemplateId: model.value.ipsecTemplateId,
    ikeKeys: model.value.ikeKeys,
    enable: model.value.enable,
    deviceMacA: model.value.deviceMacA,
    deviceMacB: model.value.deviceMacB,
    remark: model.value.remark
  };
  const { operateType } = props;
  const serviceMap = {
    add: fetchAddVPN,
    edit: fetchEditVPN
  };
  setLoading(true);
  const { response, error } = await serviceMap[operateType](params);
  setLoading(false);
  if (error) return;
  window.$message?.success(response.data.msg);
  closeDrawer();
  emit('submitted');
}

const vpnTemplateList = ref<TicketManageApi.VPNTemplateManage.Template[]>([]);
const vpnTemplateOptions = computed<CommonType.Option<number>[]>(() => {
  return vpnTemplateList.value.map(item => ({ label: item.name, value: item.id as number }));
});
/** VPN 模板中 IKE 验证算法为 与共享密钥时，则需要输入 IKE 密钥 */
const needIkeKeys = computed(() => {
  const ikeVerifyMethod = vpnTemplateList.value.find(i => i.id === model.value.ipsecTemplateId)?.ikeVerifyMethod;
  return ikeVerifyMethod === 1; /** 1 对应 PreShareKey */
});

/** 设置模板列表 */
async function setVpnTemplateList() {
  vpnTemplateList.value = [];
  const { data, error } = await fetchGetAllVPNTemplateList();
  if (error) return;
  vpnTemplateList.value = data || [];
}

watch(visible, () => {
  if (visible.value) {
    handleInitModel();
    restoreValidation();
    setVpnTemplateList();
  }
});
</script>

<template>
  <NDrawer v-model:show="visible" display-directive="show" :mask-closable="false" auto-focus :width="500">
    <NDrawerContent :title="title" :native-scrollbar="false" closable>
      <NForm ref="formRef" :model="model" :rules="rules">
        <NFormItem label="配置名称" path="name">
          <NInput v-model:value="model.name" placeholder="请输入模板名称" />
        </NFormItem>

        <NFormItem label="配置模板" path="ipsecTemplateId">
          <NSelect
            v-model:value="model.ipsecTemplateId"
            :options="vpnTemplateOptions"
            filterable
            placeholder="请选择配置模板"
          />
        </NFormItem>

        <!-- VPN 模板中 IKE 验证算法为 与共享密钥时，则需要输入 IKE 密钥 -->
        <NFormItem v-if="needIkeKeys" label="IKE密钥" path="ikeKeys">
          <NInput v-model:value="model.ikeKeys" placeholder="请输入IKE密钥" />
        </NFormItem>

        <NFormItem label="组网设备" required>
          <div class="relative w-full inline-flex items-start p-t-8px">
            <NFormItem :show-label="false" path="deviceMacA" class="flex-1" feedback-class="text-center">
              <div class="w-full flex-col-center gap-12px">
                <SvgIcon
                  local-icon="clarity-network-switch-line"
                  class="text-42px"
                  :class="{ 'text-primary': model.deviceMacA }"
                />
                <NButton ghost size="small" type="primary" @click="handleSelectDevice">
                  {{ model.deviceMacA ? `MAC：${model.deviceMacA}` : '选择组网设备' }}
                </NButton>
              </div>
            </NFormItem>
            <div class="absolute-lt w-full flex-center p-t-26px">
              <div class="relative w-[calc(50%-32px)] p-x-12px">
                <div class="line" :class="lineStatus"></div>
                <div class="absolute-center">
                  <SvgIcon
                    :local-icon="lineStatusIcon"
                    class="bg-white text-xl"
                    :class="{ 'text-error': lineStatus === 'unset', 'text-success': lineStatus === 'connecting' }"
                  />
                </div>
              </div>
            </div>
            <NFormItem :show-label="false" path="deviceMacB" class="flex-1" feedback-class="text-center">
              <div class="w-full flex-col-center gap-12px">
                <SvgIcon
                  local-icon="clarity-network-switch-line"
                  class="text-42px"
                  :class="{ 'text-primary': model.deviceMacB }"
                />
                <NButton ghost size="small" type="primary" @click="handleSelectDevice">
                  {{ model.deviceMacB ? `MAC：${model.deviceMacB}` : '选择组网设备' }}
                </NButton>
              </div>
            </NFormItem>
          </div>
        </NFormItem>

        <NFormItem label="是否启用" path="enable" label-placement="left">
          <NSwitch v-model:value="model.enable" />
        </NFormItem>

        <NFormItem label="备注" path="remark">
          <NInput
            v-model:value="model.remark"
            type="textarea"
            :autosize="{
              minRows: 3
            }"
            maxlength="500"
            show-count
            placeholder="请输入备注"
          />
        </NFormItem>
      </NForm>
      <template #footer>
        <NSpace :size="16">
          <NButton @click="closeDrawer">取消</NButton>
          <NButton type="primary" :loading="loading" @click="handleSubmit">确认</NButton>
        </NSpace>
      </template>
    </NDrawerContent>
  </NDrawer>
  <DeviceSelectModal
    v-model:visible="deviceModalVisible"
    :device-selected-mac="deviceSelectedMac"
    @submitted="handleDeviceSelect"
  />
</template>

<style lang="scss" scoped>
.line {
  --at-apply: 'w-full h-1px';
  &.connecting {
    background: repeating-linear-gradient(
      90deg,
      rgb(var(--success-color)) 0%,
      rgb(var(--success-color)) 50%,
      transparent 50%,
      transparent 100%
    );
    background-size: 10px 2px;
    animation: dash 1s linear infinite;
  }
  &.unconnected {
    background: repeating-linear-gradient(
      90deg,
      rgb(var(--base-text-color)) 0%,
      rgb(var(--base-text-color)) 50%,
      transparent 50%,
      transparent 100%
    );
    background-size: 10px 2px;
  }
  &.unset {
    background: repeating-linear-gradient(
      90deg,
      rgb(var(--error-color)) 0%,
      rgb(var(--error-color)) 50%,
      transparent 50%,
      transparent 100%
    );
    background-size: 10px 2px;
  }
  &.unenabled {
    background: repeating-linear-gradient(
      90deg,
      rgb(var(--base-text-color)) 0%,
      rgb(var(--base-text-color)) 50%,
      transparent 50%,
      transparent 100%
    );
    background-size: 10px 2px;
  }
}

@keyframes dash {
  from {
    background-position: -10px;
  }
  to {
    background-position: 0px;
  }
}
</style>
